package com.jltx.storage.downloader.net;

import com.jltx.storage.downloader.RequestException;
import com.jltx.storage.downloader.RequestResult;
import com.jltx.storage.downloader.RequestStatus;
import com.jltx.zeus.observable.AsyncMultiCall;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.ResponseBody;

/**
 * @author jltxseo
 * Created by junlintianxia on 2019/12/03.
 */
public class DownloadFileMultiCall implements AsyncMultiCall<RequestResult> {
    /**
     * 实际响应体
     */
    private ResponseBody mResponseBody;

    /**
     * 是否取消
     */
    private volatile boolean mCancel = false;

    private AsyncMultiCall.Callback<RequestResult> mCallback;
    public final String filePath;
    public final String url;


    long totalSize = 0L;
    long progressSize = 0L;

    public DownloadFileMultiCall(String filePath, String url, ResponseBody mResponseBody) {
        this.filePath = filePath;
        this.url = url;
        this.mResponseBody = mResponseBody;
    }

    @Override
    public void enqueue(Callback<RequestResult> callback) {
        mCallback = callback;
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            File futureTmpFile = new File(filePath + ".temp");
            if (!futureTmpFile.getParentFile().exists() || (futureTmpFile.getParentFile().exists() && !futureTmpFile.getParentFile().isDirectory())) {
                if (futureTmpFile.getParentFile().exists()) {
                    futureTmpFile.getParentFile().delete();
                }
                boolean isMkSuccess = futureTmpFile.getParentFile().mkdirs();
                if (!isMkSuccess) {
                    //处理错误
                    mCallback.onError(new RequestException(RequestException.CODE_ERROR_IO_EXCEPTION, "make dir file fail"));
                    return;
                }
            }
            if (futureTmpFile.exists()) {
                futureTmpFile.delete();
            }

            com.jltx.storage.downloader.net.FileResponseBody fileResponseBody = new com.jltx.storage.downloader.net.FileResponseBody(mResponseBody, new com.jltx.storage.downloader.net.FileResponseBody.LoadingChangeListener() {
                @Override
                public void onLoadingChange(long total, long progress) {
                    totalSize = total;
                    progressSize = progress;
                    if (!isCancel()) {
                        //回调下载进度
                        mCallback.onNext(new RequestResult(filePath, url, RequestStatus.STATUS_LOADING, total, progress));
                    } else {
                        mCallback.onError(new RequestException(RequestException.CODE_ERROR_CANCELED, "Canceled"));
                    }
                }
            });


            byte[] buffer = new byte[2048];
            inputStream = fileResponseBody.byteStream();
            outputStream = new FileOutputStream(futureTmpFile);
            int len;
            while ((len = inputStream.read(buffer)) != -1 && !isCancel()) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.flush();

            //判断是否已经取消
            if (isCancel()) {
                mCallback.onError(new RequestException(RequestException.CODE_ERROR_CANCELED, "Canceled"));
                return;
            }

            //下载完成之后temp后缀重命名成正式的文件名
            File saveFile = new File(filePath);
            if (saveFile.exists()) {
                saveFile.delete();
            }

            boolean isRenameSuccess = futureTmpFile.renameTo(saveFile);
            if (!isRenameSuccess) {
                mCallback.onError(new RequestException(RequestException.CODE_ERROR_IO_EXCEPTION, "rename file fail"));
                return;
            }

            //完成执行成功
            mCallback.onNext(new RequestResult(filePath, url, RequestStatus.STATUS_SUCCESS, totalSize, progressSize));
            mCallback.onComplete();

        } catch (Exception e) {
            //处理错误
            mCallback.onError(RequestException.transformException(e));
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    mCallback.onError(RequestException.transformException(e));
                }
            }

            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    mCallback.onError(RequestException.transformException(e));
                }
            }
        }

    }

    @Override
    public void cancel() {
        mCancel = true;
    }

    /**
     * 是否取消
     *
     * @return
     */
    public boolean isCancel() {
        return mCancel;
    }

}
